
C = console;

$(function(){
    var graspTree = new GRASPTree(grammar, examples["long-1"]);
    var sentenceView = new SentenceViewer(graspTree);
    var lexiconView = new Lexicon(grammar, lexicon);
    lexiconView.write();
    sentenceView.write();
});


SentenceViewer = function(graspTree) {
    this.graspTree = graspTree;
    var self = this;

    $(document).click(function(event) {
        C.log("document.click");
        if (event.button == 2) return;
        if ($("#contextmenu").is(":visible")) {
            $("#contextmenu").fadeOut("fast");
        } else {
            self.graspTree.removeSelection();
            self.updateSelection();
        }
    });

    $("#contextmenu").menu({
        select : function(event, ui) {
            C.log("#contextmenu.select", ui.item.data("tree"));
            $(this).fadeOut("fast");
            self.graspTree = ui.item.data("tree");
            self.write();
            return false;
        }
    }).hide();

    $("#sentence").click(function(event) {
        var $target = $(event.target);
        C.log("#word.click", $target.index());
        if ($("#contextmenu").is(":visible")) {
            $("#contextmenu").fadeOut("fast");
        } else if ($target.hasClass('word_selected')) {
            var success = self.graspTree.expandSelection();
            if (!success)
                self.graspTree.removeSelection();
        } else if ($target.hasClass("top_word")) {
            self.graspTree.selectNodeAtIndex(self.$words.index($target));
        } else {
            self.graspTree.removeSelection();
        }
        self.updateSelection();
        return false;
    });
    
    $("#trash").droppable({
        drop : function(event, ui) {
            C.log("#trash.drop");
            self.resetDropWord(ui.helper);
            if (ui.helper.is(".top_word")) {
                var node = self.getWordNode(ui.draggable);
                var newTrees = self.graspTree.editCommand(deletePhrase, node);
                if (newTrees && newTrees.length) {
                    self.commitChange(newTrees);
                }
            }
        },

        over : function(event, ui) {
            C.log("#trash.over", this.innerText);
            if (ui.helper.is(".top_word")) {
                var node = self.getWordNode(ui.draggable);
                var newTrees = self.graspTree.editCommand(deletePhrase, node);
                if (newTrees && newTrees.length) {
                    self.setDropValid(ui.helper);
                    return
                } 
            }
            self.setDropInvalid(ui.helper);
        },

        out : function(event, ui) {
            C.log("#trash.out");
            self.resetDropWord(ui.helper);
        },

        accept : function(draggable) {
            return true;
        }
    });
};

SentenceViewer.prototype = {
    write : function() {
        var wordArray = this.graspTree.getLin();
        var self = this;
        $("#sentence").empty();
        
        this.$words = $("#sentenceTmpl").tmpl(wordArray)
            .appendTo("#sentence")
            .filter(".word_gap")
            .droppable({
                tolerance : "pointer",

                drop : function(event, ui) {
                    C.log("#gap.drop", this.innerText);
                    self.resetDropWord(ui.helper);
                    var newTrees = self.dropOnWordGap($(this), ui.draggable);
                    if (newTrees && newTrees.length) {
                        self.commitChange(newTrees);
                    }
                },

                over : function(event, ui) {
                    C.log("#gap.over", this.innerText);
                    var newTrees = self.dropOnWordGap($(this), ui.draggable);
                    if (newTrees && newTrees.length) {
                        self.growOrShrink($(this), ui.draggable.width());
                        self.setDropValid(ui.helper);
                    } else {
                        self.setDropInvalid(ui.helper);
                    }
                },

                out : function(event, ui) {
                    C.log("#gap.out", this.innerText);
                    self.growOrShrink($(this), 0);
                    self.resetDropWord(ui.helper);
                },

                accept : function(draggable) {
                    return true;
                }
            })

            .end()
            .filter(".top_word")
            .draggable({
                distance: 20,
                stack: ".top_word",
                revert : true,
                start : function(event, ui) {
                    C.log("#word.start", this.innerText);
                },
                drag : function(event, ui) {
                    C.log("#word.drag", this.innerText);
                },
                stop : function(event, ui) {
                    C.log("#word.stop", this.innerText);
                }
            })

            .end()
            .filter(".top_word")
            .droppable({
                tolerance : "pointer",

                drop : function(event, ui) {
                    self.resetDropWord(ui.helper);
                    if (ui.helper.is(".lexicon_word")) {
                        C.log("#word.drop", this.innerText);
                        var newTrees = self.dropOnWord($(this), ui.draggable);
                        if (newTrees && newTrees.length) {
                            self.commitChange(newTrees);
                        }
                    } 
                },

                over : function(event, ui) {
                    C.log("#word.over", this.innerText);
                    if (ui.helper.is(".lexicon_word")) {
                        var newTrees = self.dropOnWord($(this), ui.draggable);
                        if (newTrees && newTrees.length) {
                            self.setClassForNodeWords(newTrees[0].getNode(), "droppable-active");
                            var width = ui.draggable.width() - $(this).width();
                            self.growOrShrink($(this), width);
                            self.setDropValid(ui.helper);
                            return;
                        }
                    }
                    self.setDropInvalid(ui.helper);
                },

                out : function(event, ui) {
                    C.log("#word.out", this.innerText);
                    self.growOrShrink($(this), 0);
                    self.resetDropWord(ui.helper);
                    $(".droppable-active").removeClass("droppable-active");
                },

                accept : function(draggable) {
                    return true;
                }
            })

            .bind("contextmenu", function() {
                C.log("#word.menu");
                self.onContextMenu($(this));
                return false;
            })

            .quickGestures({
                hold : function() {
                    C.log("#word.hold");
                    if($(this).hasClass("ui-draggable-dragging")) 
                        return;
                    self.onContextMenu($(this));
                    return false;
                }
            });

        this.updateSelection();
    },

    growOrShrink : function(elem, size) {
        elem.animate({"padding-left": size/2,
                      "padding-right": size/2
                     }, 200);
    },

    onContextMenu : function(word) {
        var node = this.getWordNode(word);
        var treeArray = this.graspTree.editCommand(similarPhrase, node);
        if (treeArray == null) {
            C.log("no context menu!");
            return false;
        }
        C.log("contextmenu.click");
        if (! word.hasClass('word_selected')) {
            this.graspTree.selectNodeAtIndex(this.$words.index(word));
            this.updateSelection();
        }
        this.buildMenu(treeArray);
        $("#contextmenu").fadeIn("fast").position({
            "my": "middle top",
            "at": "middle bottom",
            "of": word
        });
        // $(document).one("mousedown", function(event) {
        //     C.log("once", event.target, $(event.target).is(".top_word"));
        //     if(!$(event.target).is(".top_word"))
        //         $("#contextmenu").fadeIn("fast");
        // });
        return false;
    },

    dropOnWord : function(word, draggable) {
        var node = this.getWordNode(word);
        if (node == null) {
            return;
        } else if (draggable.is(".lexicon_word")) {
            var subtrees = $(draggable).tmplItem().data.trees;
            return this.graspTree.editCommand(replacePhrase, node, subtrees);
        } else {
            return;
        }
    },

    dropOnWordGap : function(wordgap, draggable) {
        var node = this.getWordNode(wordgap.next(".top_word"));
        var result;
        if (node == null) {
            return;
        } else if (draggable.is(".lexicon_word")) {
            var subtrees = $(draggable).tmplItem().data.trees;
            return this.graspTree.editCommand(insertPhrase, node, subtrees);
        } else {
            if (draggable.get(0) === wordgap.get(0) || this.isAdjacent(draggable, wordgap)) 
                return;
            var fromNode = this.getWordNode(draggable);
            var toNode = this.getWordNode(wordgap);
            return this.graspTree.editCommand(movePhrase, fromNode, toNode);
        }
    },              

    getWordNode : function($word) {
        return $word.tmplItem().data.node;
    },
    
    buildMenu : function(treeArray) {
        $("#contextmenu").empty();
        $.each(treeArray, function(i, tree) {
            var node = tree.getNode();
            var newWord = tree.getGrammar().linearise(tree.getTree().getSubtree(node));
            newWord = newWord.map(function(tok){return tok.word}).join(" ");
            $("<li/>").append($.format("<a href='%s'>%s</a>", ["#" + i, newWord])) // TODO: ta bort "#i"?
                .data("tree", tree)
                .appendTo("#contextmenu");
        });
        $("#contextmenu").menu("refresh");
    },
    
    commitChange : function(newTrees) {
        C.log("commitChange", newTrees[0]);
        var newTree = newTrees[0];
        this.graspTree = newTree;
        this.write();
    },
    
    updateSelection : function() {
        $(".word_selected").removeClass("word_selected");
        this.setClassForNodeWords(this.graspTree.getNode(), "word_selected");
    },

    setClassForNodeWords : function(node, cls) {
        var self = this;
        var indices = this.graspTree.getNodeIndices(node);
        $.each(indices, function(_, index) {
            $(self.$words[index]).addClass(cls);
        });
    },
    
    isAdjacent : function($word, $gap) {
        var gap = $gap.get(0);
        var left = $.inArray(gap, $word.prev(".word_gap")) != -1;
        var right = $.inArray(gap, $word.next(".word_gap")) != -1;
        return left || right;
    },
    
    setDropInvalid : function($word) {
        C.log("setDropInvalid");
        $("<div id='dropicon' />")
            .addClass("ui-icon")
            .addClass("ui-icon-closethick")
            .addClass("drop_invalid")
            .appendTo($word);
        if($word.is(".lexicon_word"))
            $word.css("padding-right", 14);
        else
            $word.css("margin-right", "-16px");
    },
    
    resetDropWord : function($word) {
        if($word.is(".lexicon_word"))
            $word.css("padding-right", 30);
        else
            $word.css("margin-right", 0);
        $word.find("#dropicon").remove();
        
    },
    
    setDropValid : function(word) {
        $("<div id='dropicon' />")
            .addClass("ui-icon")
            .addClass("ui-icon-circle-check")
            .addClass("drop_valid")
            .appendTo(word);
        if(word.is(".lexicon_word"))
            word.css("padding-right", 14);
        else
            word.css("margin-right", "-16px");
    },
};


Lexicon = function(grammar, lexicon) {
    this.grammar = grammar;
    this.lexicon = lexicon;
};

Lexicon.prototype.write = function() {
    var words = [];
    $.each(this.lexicon, function(key, value) {
        $.each(value, function(word, trees) {
            var graspTrees = trees.map(function(tree) {
                return new GRASPTree(this.grammar, tree);
            });
            words.push({word: word, trees: graspTrees});
        });
    });
    $("#lexiconTmpl").tmpl(words).appendTo("#wordField")
        .draggable({
            helper : "clone",
            distance: 20,
            stack: ".lexicon_word",
            revert : true,
            start : function(event, ui) {
                C.log("#lexicon.start", ui);
            },
            drag : function(event, ui) {
                C.log("#lexicon.drag", ui);
            },
            stop : function(event, ui) {
                C.log("#lexicon.stop");
            }
        });
}


